package com.sl.core.engine.datasource;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.*;
import com.google.common.collect.Maps;
import com.sl.core.engine.datasource.domain.dto.*;
import com.sl.core.engine.meta.row.ProcessRowDescriptor;
import com.sl.core.engine.plugin.domain.PluginDbTypeListDTO;
import com.sl.core.engine.utils.BeanUtil;
import com.zaxxer.hikari.HikariDataSource;
import lombok.SneakyThrows;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.anyline.data.jdbc.util.DataSourceUtil;
import org.apache.calcite.jdbc.CalciteConnection;
import org.apache.commons.compress.utils.Lists;
import org.apache.hop.core.DbCache;
import org.apache.hop.core.database.Database;
import org.apache.hop.core.database.DatabaseMeta;
import org.apache.hop.core.database.DatabasePluginType;
import org.apache.hop.core.database.IDatabase;
import org.apache.hop.core.plugins.IPlugin;
import org.apache.hop.core.plugins.PluginRegistry;
import org.apache.hop.core.row.IRowMeta;
import org.apache.hop.core.row.IValueMeta;
import org.apache.hop.core.row.RowMeta;
import org.apache.hop.core.row.value.ValueMetaFactory;
import org.apache.hop.core.variables.Variables;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.statement.*;
import org.beetl.sql.clazz.SQLType;
import org.beetl.sql.core.*;
import org.beetl.sql.core.db.DBStyle;
import org.beetl.sql.core.db.H2Style;
import org.beetl.sql.core.db.MySqlStyle;
import org.beetl.sql.core.db.SQLiteStyle;
import org.beetl.sql.core.engine.SQLPlaceholderST;
import org.beetl.sql.core.engine.template.Beetl;
import org.beetl.sql.core.engine.template.SQLTemplateEngine;
import org.beetl.sql.core.loader.SQLFileVersion;
import org.beetl.sql.core.page.DefaultPageRequest;
import org.beetl.sql.core.page.PageRequest;
import org.beetl.sql.core.page.PageResult;
import org.beetl.sql.ext.DebugInterceptor;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class DataSourceManager {

    public final static DataSourceManager INSTANCE = new DataSourceManager();

    private DataSourceQueryService dataSourceQueryService;

    private Map<String, DataSource> dataSourceMap = Maps.newConcurrentMap();

    private CalciteConnection calciteConnection;

    private Map<String, DBStyle> dbStyleMap = Maps.newHashMap();

    static {
        ProcessEnvironmentWorker.start();
    }

    @SneakyThrows
    public DataSourceManager() {
        Class.forName("org.apache.calcite.jdbc.Driver");
        // the properties for calcite connection
        Properties info = new Properties();
        info.setProperty("lex", "JAVA");
        info.setProperty("caseSensitive", "false");
        info.setProperty("remarks", "true");
        // SqlParserImpl can analysis sql dialect for sql parse
        info.setProperty("parserFactory", "org.apache.calcite.sql.parser.impl.SqlParserImpl#FACTORY");
        // create calcite connection and schema
        Connection connection = DriverManager.getConnection("jdbc:calcite:", info);
        calciteConnection = connection.unwrap(CalciteConnection.class);

        dbStyleMap.put("org.h2.Driver", new H2Style());
        dbStyleMap.put("com.mysql.cj.jdbc.Driver", new MySqlStyle());
        dbStyleMap.put("org.sqlite.JDBC", new SQLiteStyle());
    }

    public void init(DataSourceQueryService dataSourceQueryService) {
        this.dataSourceQueryService = dataSourceQueryService;
    }

    @SneakyThrows
    public String testConnection(DataSourceDTO dataSourceDTO) {
        //(String name, String type, String access, String host, String db, String port, String user, String pass)
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO);

        String s = databaseMeta.testConnection(new Variables());
        log.error(s);
        return s;
    }

    public DataSource getDataSource(String dataSourceId, Properties properties) {
        DataSource dataSource = dataSourceMap.computeIfAbsent(dataSourceId, v -> {
            DataSourceDTO dataSourceDTR = dataSourceQueryService.queryById(v, properties);
            DataSource ds = buildDataSource(dataSourceDTR);
            return ds;
        });
        if (dataSource instanceof HikariDataSource hikariDataSource) {
            if (hikariDataSource.isClosed()) {
                dataSourceMap.remove(dataSourceId);
                return getDataSource(dataSourceId, properties);
            }
        }
        return dataSource;

    }

    @Synchronized
    public DataSource getDataSource(DataSourceDTO dataSourceDTO) {

        DataSource dataSource = getDataSource(dataSourceDTO.getId(), dataSourceDTO.getProperties());

        if (dataSource instanceof HikariDataSource hikariDataSource) {
            dataSourceDTO.setDriverClassName(hikariDataSource.getDriverClassName());
            dataSourceDTO.setUsername(hikariDataSource.getUsername());
            dataSourceDTO.setPassword(hikariDataSource.getPassword());
            dataSourceDTO.setUrl(hikariDataSource.getJdbcUrl());
        }
        return dataSource;
    }


    public DataSourceDTO getDataSourceById(String rowSetTagDataSourceId) {
        DataSourceDTO dataSourceDTR = dataSourceQueryService.queryById(rowSetTagDataSourceId, null);
        return dataSourceDTR;
    }

    private SlDatabaseMeta getDatabaseMeta(DataSourceDTO dataSourceDTO, String catalogName) {
        String dc = dataSourceDTO.getDb();
        if (StrUtil.isNotBlank(catalogName)) {
            dataSourceDTO.setDb(catalogName);
        }

        SlDatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO);
        //库名替换
        String manualUrl = databaseMeta.getManualUrl();
        if (StrUtil.isNotBlank(manualUrl) && StrUtil.isNotBlank(catalogName)) {
            databaseMeta.setManualUrl(StrUtil.replace(manualUrl, dc, catalogName));
        }
        return databaseMeta;
    }

    private SlDatabaseMeta getDatabaseMeta(DataSourceDTO dataSourceDTO) {
        SlDatabaseMeta databaseMeta = new SlDatabaseMeta(dataSourceDTO.getDatasourceCode(), dataSourceDTO.getDbTypeCode(),
                //jdbc
                "Native", dataSourceDTO.getIp(), dataSourceDTO.getDb(), dataSourceDTO.getPort(), dataSourceDTO.getUsername(), dataSourceDTO.getPassword());
        String url = dataSourceDTO.getUrl();
        if (StrUtil.isNotBlank(url)) {
            databaseMeta.setManualUrl(url);
        }

        Properties properties = dataSourceDTO.getProperties();

        Map<String, String> attributes = databaseMeta.getAttributes();
        if (ObjectUtil.isNull(attributes)) {
            databaseMeta.setAttributes(new HashMap<>());

        }
        if (ObjectUtil.isNotNull(properties)) {
            Map<String, String> collect = properties.entrySet().stream().collect(Collectors.toMap(v -> v.getKey().toString(), v -> v.getValue().toString()));
            databaseMeta.getAttributes().putAll(collect);
        }
        if (StrUtil.isBlank(dataSourceDTO.getDatasourceName())) {
            dataSourceDTO.setDatasourceName(IdUtil.getSnowflakeNextIdStr());
        }
        databaseMeta.setName(dataSourceDTO.getDatasourceName());
        return databaseMeta;
    }

    @SneakyThrows
    public List<PluginDbTypeListDTO> getDbTypeList() {
        PluginRegistry registry = PluginRegistry.getInstance();
        List<IPlugin> plugin = registry.getPlugins(DatabasePluginType.class);
        List<PluginDbTypeListDTO> maps = Lists.newArrayList();
        for (IPlugin pluginInterface : plugin) {
            PluginDbTypeListDTO pluginDbTypeListDTO = new PluginDbTypeListDTO();
            pluginDbTypeListDTO.setId(pluginInterface.getIds()[0]);
            pluginDbTypeListDTO.setName(pluginInterface.getName());
            List<String> driverClassList = Lists.newArrayList();
            IDatabase databaseInterface = DatabaseMeta.getIDatabase(pluginDbTypeListDTO.getId());
            String driverClass = databaseInterface.getDriverClass();
            driverClassList.add(driverClass);
            pluginDbTypeListDTO.setDriverClass(driverClassList);
            maps.add(pluginDbTypeListDTO);
        }
        return maps;
    }

    @SneakyThrows
    public String getUrl(DataSourceDTO dataSourceDTO) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO);
        return databaseMeta.getURL(new Variables());
    }

    @SneakyThrows
    public String[] querySchemaList(DataSourceDTO dataSourceDTO) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO);
        if (!BooleanUtil.isTrue(databaseMeta.supportsSchemas())) {
            return new String[]{};
        }

        Database db = new Database(null, new Variables(), databaseMeta);
        db.connect();

        String[] schemas = db.getSchemas();
        return schemas;
    }

    private DataSource buildDataSource(DataSourceDTO dataSourceDTO) {
        Map<String, Object> maps = Maps.newConcurrentMap();
        maps.put("url", dataSourceDTO.getUrl());
        maps.put("driver", dataSourceDTO.getDriverClassName());
        maps.put("username", dataSourceDTO.getUsername());
        maps.put("password", dataSourceDTO.getPassword());
        maps.put("type", HikariDataSource.class.getName());
        DataSource dataSource = DataSourceUtil.build(maps);
        return dataSource;
    }

    public Boolean supportsSchemas(DataSourceDTO dataSourceDTO) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO);
        return databaseMeta.supportsSchemas();

    }

    @SneakyThrows
    public String[] queryCatalogList(DataSourceDTO dataSourceDTO) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO);
        if (!BooleanUtil.isTrue(databaseMeta.supportsCatalogs())) {
            return new String[]{};
        }

        Database db = new Database(null, new Variables(), databaseMeta);
        db.connect();

        String[] schemas = db.getCatalogs();
        return schemas;
    }

    public Boolean supportsCatalogs(DataSourceDTO dataSourceDTO) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO);
        return databaseMeta.supportsCatalogs();

    }

    @SneakyThrows
    public List<String> queryTableList(DataSourceDTO dataSourceDTO, String catalogName) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);
        Database db = new SlDatabase(null, new Variables(), databaseMeta);
        db.connect();

        Map<String, Collection<String>> tableMap = db.getTableMap(catalogName);

//        AnylineService anylineService = anylineService(dataSourceDTO);
//        Catalog catalog = new Catalog();
//        catalog.setName(catalogName);
//        Schema schema  =new Schema();
//        schema.setName(catalogName);
//        anylineService.metadata().tables(null,schema,null,0,0);

        List<String> list = MapUtil.get(tableMap, catalogName, List.class);

        return CollUtil.sort(list, Comparator.comparing(b -> b));
    }

    @SneakyThrows
    public ProcessRowDescriptor queryTableFieldList(DataSourceDTO dataSourceDTO, String catalogName, String tableName) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);

        Database db = new Database(null, new Variables(), databaseMeta);
        db.connect();
        DbCache instance = DbCache.getInstance();
        instance.clear(null);

        IRowMeta tableFields = db.getTableFields(tableName);
        return new ProcessRowDescriptor(tableFields);
//        return tableFields.toStringMeta();
    }

    @SneakyThrows
    public String queryTableDdl(DataSourceDTO dataSourceDTO, String tableName) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO);
        Database db = new Database(null, new Variables(), databaseMeta);
        db.connect();
        IRowMeta tableFields = db.getTableFields(tableName);

        String ddlCreationTable = db.getDDLCreationTable(tableName, tableFields);
        return ddlCreationTable;
    }

    public List<Map<String, Object>> run(String datasourceId, String sql, Map<String, Object> map) {
        DataSourceDTO dataSourceDTO = new DataSourceDTO();
        dataSourceDTO.setId(datasourceId);
        return pageBody(dataSourceDTO, sql, map, 1, Integer.MAX_VALUE, false);
    }

    public PageResult<Map<String, Object>> page(String datasourceId, String sql, Map<String, Object> params, Integer currentPage, Integer pageSize) {
        DataSourceDTO dataSourceDTO = new DataSourceDTO();
        dataSourceDTO.setId(datasourceId);
        return page(dataSourceDTO, sql, params, currentPage, pageSize, true);
    }

    private List<Map<String, Object>> pageBody(DataSourceDTO dataSourceDTO, String sql, Map<String, Object> params, Integer currentPage, Integer pageSize, boolean totalRequired) {
        PageResult page = page(dataSourceDTO, sql, params, currentPage, pageSize, totalRequired);
        if (ObjectUtil.isNull(page)) {
            return Collections.emptyList();
        }
        return page.getList();
    }

    private PageResult page(DataSourceDTO dataSourceDTO, String sql, Map<String, Object> params, Integer currentPage, Integer pageSize, boolean totalRequired) {
        DataSource dataSource = getDataSource(dataSourceDTO);

        ConnectionSource source = ConnectionSourceHelper.getSingle(dataSource);
//source是唯一必须的参数，其他参数都有默认值
        SQLManagerBuilder builder = new SQLManagerBuilder(source);
//设置NameConversion，这里数据库命名采用下划线风格，使用UnderlinedNameConversion
        builder.setNc(new DefaultNameConversion());
//设置一个拦截器，输出debug日志，包含了sql语句和执行参数，执行时间
        builder.setInters(new Interceptor[]{new DebugInterceptor()});
//设置数据库分隔，必须跟数据库一样
        builder.setDbStyle(dbStyleMap.get(dataSourceDTO.getDriverClassName()));
        SQLManager sqlManager = builder.build();

        PageRequest request = DefaultPageRequest.of(currentPage, pageSize, totalRequired);
//        SQLReady sqlReady = new SQLReady(sql);

        PageResult pageResult = SlSQLManager.executePageQuery(sqlManager, sql, Map.class, params, request);

//        PageResult pageResult = sqlManager.executePageQuery(sql, Map.class, params, request);
        return pageResult;
    }

    @SneakyThrows
    public SqlQueryResultDTO run(DataSourceDTO dataSourceDTO, String sql, Map<String, Object> map) {
        SqlQueryResultDTO sqlQueryResultDTO = new SqlQueryResultDTO();


        long start = System.currentTimeMillis();
        List<Map<String, Object>> list = null;
        try {
            //不查询 total
            list = this.pageBody(dataSourceDTO, sql, map, 1, 10, false);

        } catch (Exception e) {
            log.error("查询数据库报错了", e);
            sqlQueryResultDTO.setMessage(e.getMessage());
            sqlQueryResultDTO.setTime(System.currentTimeMillis() - start);
            return sqlQueryResultDTO;
        }
        long end = System.currentTimeMillis();
        sqlQueryResultDTO.setTime(end - start);
        sqlQueryResultDTO.setRows(BeanUtil.convert(list));

        List<String> strings = Lists.newArrayList();

        IRowMeta queryFields = getQueryFields(dataSourceDTO, sql);
        if (ObjectUtil.isNotNull(queryFields)) {
            for (IValueMeta valueMeta : queryFields.getValueMetaList()) {
                strings.add(valueMeta.getName());
            }
        }
        sqlQueryResultDTO.setHeaders(strings);
        return sqlQueryResultDTO;
    }

    @SneakyThrows
    public IRowMeta getQueryFields(String datasourceId, String sql) {
        DataSourceDTO dataSourceDTO = dataSourceQueryService.queryById(datasourceId, null);
        return getQueryFields(dataSourceDTO, sql);
    }

    @SneakyThrows
    public IRowMeta getQueryFields(DataSourceDTO dataSourceDTO, String sql) {

        if (ObjectUtil.isNull(dataSourceDTO)) {
            return null;
        }
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO);
        Database db = new Database(null, new Variables(), databaseMeta);
        db.connect();
        //这里要获取所有的变量生成临时变量
        ConnectionSource source = ConnectionSourceHelper.getSingle(getDataSource(dataSourceDTO));
//source是唯一必须的参数，其他参数都有默认值
        SQLManagerBuilder builder = new SQLManagerBuilder(source);
//设置NameConversion，这里数据库命名采用下划线风格，使用UnderlinedNameConversion
        builder.setNc(new DefaultNameConversion());
//设置一个拦截器，输出debug日志，包含了sql语句和执行参数，执行时间
        builder.setInters(new Interceptor[]{new DebugInterceptor()});
//设置数据库分隔，必须跟数据库一样
        builder.setDbStyle(dbStyleMap.get(dataSourceDTO.getDriverClassName()));
        SQLManager sqlManager = builder.build();

        SqlId sqlId = sqlManager.getSqlIdFactory().buildTemplate(sql);

        SQLSource sqlSource = new SQLSource();
        sqlSource.setTemplate(sql);
        sqlSource.setId(sqlId);
        sqlSource.setSqlType(SQLType.SELECT);
        SQLFileVersion sqlFileVersion = new SQLFileVersion();
        sqlSource.setVersion(sqlFileVersion);

        sqlManager.getSqlLoader().addSQL(sqlId, sqlSource);

        SQLTemplateEngine sqlTemplateEngine = sqlManager.getSqlTemplateEngine();

        Object beetl = ReflectUtil.getFieldValue(sqlTemplateEngine, "beetl");

        Map<String, Object> map = Maps.newHashMap();
        if (ObjectUtil.isNotNull(beetl)) {
            Beetl bt = (Beetl) beetl;
            GroupTemplate groupTemplate = bt.getGroupTemplate();
            Template template = groupTemplate.getTemplate(sqlId);
            ProgramMetaData metaData = template.program.metaData;

            replaceSqlTemplateVariable(metaData, map);

            SQLResult sqlResult = sqlManager.getSQLResult(sqlSource, map);
            sql = sqlResult.jdbcSql;
        }

        IRowMeta queryFields = db.getQueryFields(sql, true, null,
                map.values().toArray(new Object[0]));

        return queryFields;
    }

    private void replaceSqlTemplateVariable(ProgramMetaData metaData, Map<String, Object> map) {
        Statement[] statements = metaData.statements;
        for (Statement statement : statements) {
            if (statement instanceof StaticTextASTNode) {
                continue;
            }

            if (statement instanceof SQLPlaceholderST sqlPlaceholderST) {

                Expression expression = sqlPlaceholderST.expression;

                if (expression instanceof VarRef varRef) {
                    GrammarToken token = expression.token;


                    VarAttribute[] attributes = varRef.attributes;
                    if (ArrayUtil.isEmpty(attributes)) {
                        map.put(token.toString(), StrUtil.EMPTY);
                        continue;
                    } else {
                        Map<String, Object> subVarAttrMap = Maps.newHashMap();
                        map.put(token.toString(), subVarAttrMap);
                        for (VarAttribute attribute : attributes) {
                            if (attribute instanceof VarSquareAttribute varSquareAttribute) {
                                map.put(token.toString(), Lists.newArrayList());
                                continue;
                            }
                            Object o = map.get(token.toString());

                            if (o instanceof Collection collection) {
                                GrammarToken tk = attribute.token;
                                Map<String, Object> v = Maps.newHashMap();
                                v.put(tk.toString(), StrUtil.EMPTY);
                                collection.add(v);
                            } else {
                                GrammarToken tk = attribute.token;
                                subVarAttrMap.put(tk.toString(), StrUtil.EMPTY);
                            }


                        }
                    }
                }
            }

        }
    }

    @SneakyThrows
    public List<TableIndexDTO> queryTableIndexList(DataSourceDTO dataSourceDTO, String catalogName, String tableName) {
        SlDatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);
        SlDatabase db = new SlDatabase(null, new Variables(), databaseMeta);
        db.connect();

        List<IValueMeta> indexList = db.getIndexList(tableName);
        Map<String, List<IValueMeta>> collect = indexList.stream().collect(Collectors.groupingBy(IValueMeta::getName));

        return collect.entrySet().stream().map(v -> {
            String key = v.getKey();
            List<IValueMeta> value = v.getValue();

            TableIndexDTO tableColumnDTO = new TableIndexDTO();
            tableColumnDTO.setColumnNameList(value.stream().map(IValueMeta::getComments).collect(Collectors.toList()));
            tableColumnDTO.setIndexName(key);
            return tableColumnDTO;
        }).collect(Collectors.toList());
    }

    @SneakyThrows
    public List<TableKeysDTO> queryKeysList(DataSourceDTO dataSourceDTO, String catalogName, String tableName) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);
        Database db = new Database(null, new Variables(), databaseMeta);
        db.connect();


        String[] primaryKeyColumnNames = db.getPrimaryKeyColumnNames(tableName);
        List<TableKeysDTO> collect = Arrays.stream(primaryKeyColumnNames).map(v -> {
            TableKeysDTO tableKeysDTO = new TableKeysDTO();
            tableKeysDTO.setIsPrimary(true);
            tableKeysDTO.setColumnName(v);
            return tableKeysDTO;
        }).collect(Collectors.toList());

        return collect;
    }

    @SneakyThrows
    public Boolean addUpdateTable(DataSourceDTO dataSourceDTO, String catalogName, String tableName, String sourceTableName) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);
        SlDatabase db = new SlDatabase(null, new Variables(), databaseMeta);
        db.connect();
        String ddlCreationTable = null;
        if (StrUtil.isNotBlank(sourceTableName)) {
            ddlCreationTable = db.getDDLModifyTable(sourceTableName, tableName);
        } else {
            IRowMeta iRowMeta = new RowMeta();
            ddlCreationTable = db.getDDLCreationTable(tableName, iRowMeta);


        }
        if (StrUtil.isBlank(ddlCreationTable)) {
            return Boolean.FALSE;
        }
        db.execStatement(ddlCreationTable);
        return Boolean.TRUE;

    }

    @SneakyThrows
    public Boolean removeTable(DataSourceDTO dataSourceDTO, String catalogName, String tableName) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);
        SlDatabase db = new SlDatabase(null, new Variables(), databaseMeta);
        db.connect();

        String ddlCreationTable = db.removeTable(tableName);

        db.execStatement(ddlCreationTable);
        return Boolean.TRUE;
    }

    @SneakyThrows
    public Boolean addUpdateIndex(DataSourceDTO dataSourceDTO, String catalogName, String tableName, String indexName, String sourceIndexName,
                                  List<String> fieldNameList) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);
        SlDatabase db = new SlDatabase(null, new Variables(), databaseMeta);
        db.connect();
        String ddlCreationTable = null;
        if (StrUtil.isNotBlank(sourceIndexName)) {

        } else {
            ddlCreationTable = db.getCreateIndexStatement(catalogName, tableName, indexName,
                    fieldNameList.stream().toArray(String[]::new), false, false, false, false);
        }
        if (StrUtil.isBlank(ddlCreationTable)) {
            return Boolean.FALSE;
        }
        db.execStatement(ddlCreationTable);
        return Boolean.TRUE;

    }

    @SneakyThrows
    public String queryCreateTableFieldList(DataSourceDTO dataSourceDTO, String catalogName, String tableName, List<TableColumnDTO> columnList) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);
        SlDatabase db = new SlDatabase(null, new Variables(), databaseMeta);
        db.connect();

        IRowMeta iRowMeta = new RowMeta();

        for (TableColumnDTO tableColumnDTO : columnList) {
            Integer i = ProcessRowDescriptor.outFieldTypeTransfer(tableColumnDTO.getColumnType());
            IValueMeta valueMeta = ValueMetaFactory.createValueMeta(i);
            valueMeta.setName(tableColumnDTO.getColumnName());
            valueMeta.setComments(tableColumnDTO.getComment());
            valueMeta.setLength(Integer.valueOf(tableColumnDTO.getColumnLength()));
            iRowMeta.addValueMeta(valueMeta);
        }

        String ddl = db.getDDL(tableName, iRowMeta);
        return ddl;
    }

    @SneakyThrows
    public Boolean executeDdl(DataSourceDTO dataSourceDTO, String catalogName, String tableName, String ddl) {

        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);
        SlDatabase db = new SlDatabase(null, new Variables(), databaseMeta);
        db.connect();
        db.execStatement(ddl);
        return Boolean.TRUE;
    }

    @SneakyThrows
    public String queryUpdateTableFieldList(DataSourceDTO dataSourceDTO, String catalogName, String tableName, List<TableColumnDTO> columnList) {

        return null;
    }

    @SneakyThrows
    public Boolean dropIndex(DataSourceDTO dataSourceDTO, String catalogName, String tableName, String indexName) {
        DatabaseMeta databaseMeta = getDatabaseMeta(dataSourceDTO, catalogName);
        SlDatabase db = new SlDatabase(null, new Variables(), databaseMeta);
        db.connect();

        String ddlCreationTable = db.getRemoveIndexStatement(catalogName, tableName, indexName);

        if (StrUtil.isBlank(ddlCreationTable)) {
            return Boolean.FALSE;
        }
        db.execStatement(ddlCreationTable);
        return Boolean.TRUE;
    }

    public void clear() {
        dataSourceMap.clear();
    }

}
